package com.yiyihealth.cherriesadmin.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.Week;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yiyihealth.cherriesadmin.core.http.HttpResult;
import com.yiyihealth.cherriesadmin.core.service.impl.BaseServiceImpl;
import com.yiyihealth.cherriesadmin.core.smsInterface.AliyunSmsUtil;
import com.yiyihealth.cherriesadmin.core.utils.JKTUtil;
import com.yiyihealth.cherriesadmin.core.webservice.MainServiceImplPortType;
import com.yiyihealth.cherriesadmin.core.webservice.MainServiceImplPortTypeService;
import com.yiyihealth.cherriesadmin.mapper.*;
import com.yiyihealth.cherriesadmin.model.*;
import com.yiyihealth.cherriesadmin.model.his.ExecutionResult;
import com.yiyihealth.cherriesadmin.model.jkt.*;
import com.yiyihealth.cherriesadmin.model.wrapper.OrdSchedulingWrapper;
import com.yiyihealth.cherriesadmin.service.OrdSchedulingService;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.yiyihealth.cherriesadmin.core.utils.JKTUtil.sortMap;

/**
 * 日常排版(OrdScheduling)表服务实现类
 *
 * @author chen
 * @since 2020-09-14 20:03:29
 */
@Transactional
@Service("ordSchedulingService")
@CacheConfig(cacheNames = "scheduling")
public class OrdSchedulingServiceImpl extends BaseServiceImpl<OrdScheduling, OrdSchedulingWrapper, Long> implements OrdSchedulingService {
    @Resource
    private OrdSchedulingMapper ordSchedulingMapper;
    @Resource
    private OrdSourceDetailMapper ordSourceDetailMapper;
    @Resource
    private OrdAppointmentMapper ordAppointmentMapper;
    @Resource
    private PubHospitalMapper pubHospitalMapper;
    @Resource
    private PubDepartmentsMapper departmentsMapper;
    @Resource
    private PubDoctorMapper doctorMapper;
    @Resource
    private PubPatientsMapper patientsMapper;
    @Resource
    private RedisTemplate<Object, Object> redisCacheTemplate;
    @Resource
    private OrdSchedulingHistoryMapper ordSchedulingHistoryMapper;
    @Resource
    private OrdSourceDetailHistoryMapper ordSourceDetailHistoryMapper;
    @Resource
    private PubBindInfoMapper pubBindInfoMapper;

    @Resource
    private JktFunc10004 jktFunc10004;
    @Resource
    private JktFunc10005 jktFunc10005;
    @Resource
    private JktFunc10006 jktFunc10006;
    @Resource
    private JktFunc10007 jktFunc10007;
    @Resource
    private JThealth jThealth;

    @Autowired
    private void setEntityMapper() {
        super.setEntityMapper(ordSchedulingMapper);
    }

    /**
     * 停诊
     *
     * @param id
     * @param reason
     * @return
     */
    @Override
    public String doctorStopWork(Long id, String reason) throws Exception {
        OrdScheduling scheduling = ordSchedulingMapper.selectByPrimaryKey(id);
        scheduling.setStatus(scheduling.getStatus().equals("1") ? "0" : "1");
        scheduling.setStopServiceReason(reason);

        if (scheduling.getStatus().equals("0")) {
            Map<String, Object> schedulingMap = new HashMap<String, Object>(8);
            schedulingMap.put("templateId", scheduling.getId());
            schedulingMap.put("schedulingTime", scheduling.getSchedulingTime());
            schedulingMap.put("status", "0");
            schedulingMap.put("hospitalId", scheduling.getHospitalId());
            List<OrdScheduling> schedulingList = ordSchedulingMapper.selectList(schedulingMap);
            if (!CollectionUtil.isEmpty(schedulingList)) {
                throw new Exception(scheduling.getDepName() + scheduling.getDoctorName() + "的" + LocalDateTimeUtil.format(scheduling.getSchedulingTime(), DatePattern.CHINESE_DATE_PATTERN) + "的排班已存在，不能恢复排班！");
            }
        }

        Map<String, Object> schedulingMap = new HashMap<String, Object>(8);
        schedulingMap.put("schedulingId", id);
        List<OrdSourceDetail> sourceDetailList = ordSourceDetailMapper.selectList(schedulingMap);
        if (!CollectionUtil.isEmpty(sourceDetailList)) {
            for (OrdSourceDetail sourceDetail : sourceDetailList) {
                sourceDetail.setStatus(scheduling.getStatus());
                //使用状态(1窗口挂号 2平台预约取号 3平台爽约 4院内预约取号 5院内爽约 6退号 7医生停诊)
                if (sourceDetail.getState().equals("0")) {
                    sourceDetail.setState("7");
                } else if (sourceDetail.getState().equals("7")) {
                    sourceDetail.setState("0");
                }
                ordSourceDetailMapper.updateByPrimaryKeySelective(sourceDetail);
            }
        }
        if (scheduling.getStopServiceReason().equals("") || scheduling.getStopServiceReason() == null) {
            scheduling.setStopServiceReason("医生因私停诊");
        }
        ordSchedulingMapper.updateByPrimaryKeySelective(scheduling);

        //缓存清除
        String sourceDetailKey = "sourceDetail:" + scheduling.getDoctorId() + ":" + scheduling.getId();
        String schedulingKey = "scheduling:" + scheduling.getDoctorId() + ":" + scheduling.getId();

        Map<String, Object> appointmentMap = new HashMap<String, Object>(8);
        appointmentMap.put("schedulingId", id);
        //注销
        if (scheduling.getStatus().equals("1")) {
            redisCacheTemplate.delete(schedulingKey);
            redisCacheTemplate.delete(sourceDetailKey);
            appointmentMap.put("appStatus", 0);
        } else if (scheduling.getStatus().equals("0")) {
            //设置过期时间
            Duration duration = Duration.between(LocalDateTime.now(), scheduling.getSchedulingTime().atTime(23, 59, 59));
            redisCacheTemplate.opsForValue().set(schedulingKey, scheduling.getAmount(), duration);
            sourceDetailList.forEach(ordSourceDetail -> {
                if (ordSourceDetail.getState().equals("0")) {
                    redisCacheTemplate.opsForSet().add(sourceDetailKey, ordSourceDetail.getId());
                }
            });
            redisCacheTemplate.expire(sourceDetailKey, duration);
            appointmentMap.put("appStatus", 4);
        }
        List<OrdAppointment> appointmentList = ordAppointmentMapper.selectList(appointmentMap);
        PubHospital hospital = pubHospitalMapper.selectByPrimaryKey(scheduling.getHospitalId());
        for (OrdAppointment appointment : appointmentList) {
            //预约状态(0已预约 1已过期 2已取号 3患者取消 4医生停诊 5后台取消)
            if (appointment.getAppStatus().equals(4)) {
                appointment.setAppStatus(0);
                //取消停诊--您好${patName},您预约${hosName}的${date}的${depName}门诊${doctorName}医生姓名:${ampm}第${serialNumber}号已取消停诊,你的取号密码：${password}。${tip}详情请咨询：${phone}。
                ordAppointmentMapper.updateByPrimaryKeySelective(appointment);
                JSONObject cancelAppointmentReminder = new JSONObject();
                cancelAppointmentReminder.set("patName", appointment.getPatName());
                cancelAppointmentReminder.set("hosName", hospital.getHosName());
                cancelAppointmentReminder.set("date", LocalDateTimeUtil.format(appointment.getVisitDate(), DatePattern.CHINESE_DATE_PATTERN));
                cancelAppointmentReminder.set("depName", appointment.getDepName());
                cancelAppointmentReminder.set("ampm", scheduling.getTimeState().equals(1) ? "上午" : scheduling.getTimeState().equals(2) ? "下午" : "夜门诊");
                cancelAppointmentReminder.set("doctorName", appointment.getDoctorName());
                cancelAppointmentReminder.set("serialNumber", appointment.getSerialNumber());
                cancelAppointmentReminder.set("phone", hospital.getHosPhone());
                cancelAppointmentReminder.set("password", appointment.getPassword());
                cancelAppointmentReminder.set("tip", scheduling.getTip() == null ? "" : scheduling.getTip());
                AliyunSmsUtil.sendSms(appointment.getPhone(), "SMS_205621478", cancelAppointmentReminder.toString());
            } else {
                appointment.setAppStatus(4);
                //取消预约--您好${patName},您预约${hosName}的${date}的${depName}门诊${doctorName}医生${ampm}第${serialNumber}号已停诊，停诊原因：${reason}。详情请咨询：${phone}。
                //SMS_205400882
                ordAppointmentMapper.updateByPrimaryKeySelective(appointment);
                //调用HIS接口推送数据到HIS
                ExecutionResult executionResult = deleteDataHIS(appointment);
                if (executionResult.getOutResult().equals(0)) {
                    JSONObject cancelAppointmentReminder = new JSONObject();
                    cancelAppointmentReminder.set("patName", appointment.getPatName());
                    cancelAppointmentReminder.set("hosName", hospital.getHosName());
                    cancelAppointmentReminder.set("date", LocalDateTimeUtil.format(appointment.getVisitDate(), DatePattern.CHINESE_DATE_PATTERN));
                    cancelAppointmentReminder.set("depName", appointment.getDepName());
                    cancelAppointmentReminder.set("ampm", scheduling.getTimeState().equals(1) ? "上午" : scheduling.getTimeState().equals(2) ? "下午" : "夜门诊");
                    cancelAppointmentReminder.set("doctorName", appointment.getDoctorName());
                    cancelAppointmentReminder.set("serialNumber", appointment.getSerialNumber());
                    cancelAppointmentReminder.set("phone", hospital.getHosPhone());
                    AliyunSmsUtil.sendSms(appointment.getPhone(), "SMS_206561400", cancelAppointmentReminder.toString());
                } else {
                    throw new Exception(executionResult.getOutData());
                }
            }
        }
        SchedulingCancelFunMain(hospital, scheduling);
        jktCancel(scheduling);
        return "";
    }

    /**
     * 取消HIS预约
     *
     * @param record
     * @return
     * @throws Exception
     */
    private ExecutionResult deleteDataHIS(OrdAppointment record) throws Exception {
        StringBuilder inData = new StringBuilder();
        PubHospital hospital = pubHospitalMapper.selectByPrimaryKey(record.getHospitalId());
        //取消HIS中的预约数据
        //20151122|69514581|3031307
        //就诊日期 Timestamp 格式：YYYYMMDD 否
        inData.append(LocalDateTimeUtil.format(record.getVisitDate(), DatePattern.PURE_DATE_PATTERN) + "|");
        //取号密码 String(8) 8 位的取号密码，一周内不可重复，可 0 否浙江省医院预约诊疗服务系统医院接入规范 第 30 页 开头，不可字母。
        inData.append(record.getPassword() + "|");
        //用户编号 String
        inData.append(record.getPatId().toString());
        String tokenStr = "";
        try {
            tokenStr = HttpUtil.post(hospital.getHosRegionalCode() + "/cancel/storedProcedure", "inData=" + inData.toString());
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("第三方接口异常");
        }
        HttpResult httpResult = JSONUtil.toBean(JSONUtil.parseObj(tokenStr), HttpResult.class);
        ExecutionResult executionResult = JSONUtil.toBean(JSONUtil.parseObj(httpResult.getData()), ExecutionResult.class);
        return executionResult;
    }

    private void SchedulingCancelFunMain(PubHospital hospital, OrdScheduling scheduling) throws DocumentException {
        MainServiceImplPortType service = new MainServiceImplPortTypeService().getMainServiceImplPortTypePort();
        String strResult = "";

        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("data");
        Element funcode = root.addElement("funcode");
        if (scheduling.getStatus().equals("1")) {
            funcode.setText("200104");
        } else {
            funcode.setText("200105");
        }
        //1. 排班编号 schid 32 N停诊的排班在医院的唯一编号
        Element schid = root.addElement("schid");
        schid.setText(scheduling.getId().toString());

        //2. 医院编号 orgid 32 N单医院接入传空，地市平台接入传医院在地市平台的编号
        Element orgid = root.addElement("orgid");
        orgid.setText(hospital.getHosMarkCode());

        //3. 上下午标志 ampm 2 N 1-上午 2-下午
        Element ampm = root.addElement("ampm");
        ampm.setText(scheduling.getTimeState().equals(3) ? "2" : scheduling.getTimeState().toString());
        // 1 停诊 0 取消停诊
        if (scheduling.getStatus().equals("1")) {
            //4. 停诊原因 reason 3 N 见停诊原因对照表
            Element reason = root.addElement("reason");
            reason.setText("11");
        }


        //5. 停诊日期 schdate 8 N格式：YYYYMMDD
        Element schdate = root.addElement("schdate");
        schdate.setText(LocalDateTimeUtil.format(scheduling.getSchedulingTime(), DatePattern.PURE_DATE_PATTERN));

        strResult = service.funMain(document.asXML());
        Document documentResult = DocumentHelper.parseText(strResult);
        //获取根节点
        Element rootElt = documentResult.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        //获取子节点
        Element stateElt = rootElt.element("state");
        Element resultElt = rootElt.element("result");

    }



    @Override
    public String schedulingCache(OrdScheduling scheduling) throws Exception {
        HashSet<String> hashSet = generateAppointmentSet(scheduling);
        Map<String, Object> sourceDetailMap = new HashMap<String, Object>(8);
        sourceDetailMap.put("schedulingId", scheduling.getId());
        sourceDetailMap.put("status", "0");
        List<OrdSourceDetail> sourceDetailList = ordSourceDetailMapper.selectList(sourceDetailMap);
        //设置过期时间
        Duration duration = Duration.between(LocalDateTime.now(), scheduling.getSchedulingTime().atTime(23, 59, 59));
        String schedulingKey = "scheduling:" + scheduling.getDoctorId() + ":" + scheduling.getId();
        if (redisCacheTemplate.hasKey(schedulingKey)) {
            redisCacheTemplate.delete(schedulingKey);
        }
        try {
            redisCacheTemplate.opsForValue().set(schedulingKey, scheduling.getAmount(), duration);
        }catch (Exception e){
            System.out.println(scheduling.toString());
            throw new Exception(e.getMessage());
        }
        String sourceDetailKey = "sourceDetail:" + scheduling.getDoctorId() + ":" + scheduling.getId();
        if (redisCacheTemplate.hasKey(sourceDetailKey)) {
            redisCacheTemplate.delete(sourceDetailKey);
        }
        for (OrdSourceDetail sourceDetail : sourceDetailList) {
            if (sourceDetail.getStatus().equals("0")) {
                if (hashSet.contains(sourceDetail.getSerialNumber())) {
                    sourceDetail.setType("1");
                } else {
                    sourceDetail.setType("0");
                }
                redisCacheTemplate.opsForSet().add(sourceDetailKey, sourceDetail.getId());
            }
        }
        sourceDetailList.forEach(ordSourceDetail -> {
            redisCacheTemplate.opsForSet().add(sourceDetailKey, ordSourceDetail.getId());
        });
        redisCacheTemplate.expire(sourceDetailKey, duration);
        return "";
    }


    /**
     * 定时任务每天23点把一个星期以前的排班转移到历史库中
     *
     * @return
     * @throws Exception
     */
    @Scheduled(cron = " 0 40 23 ? * *")
    @Override
    public synchronized boolean schedulingtasks() throws Exception {
        Map<String, Object> map = new HashMap<>();
        map.put("startDate",LocalDateTimeUtil.format(LocalDate.now().minusMonths(12),"yyyy-MM-dd"));
        map.put("endDate",LocalDateTimeUtil.format(LocalDate.now(),"yyyy-MM-dd"));
        List<OrdScheduling> list = ordSchedulingMapper.selectList(map);
        for (OrdScheduling ordScheduling : list) {
            //传值对象
            OrdSchedulingHistory ordSchedulingHistory = new OrdSchedulingHistory();
            BeanUtil.copyProperties(ordScheduling, ordSchedulingHistory);
            ordSchedulingHistoryMapper.insert(ordSchedulingHistory);
            ordSchedulingMapper.deleteByPrimaryKey(ordScheduling.getId());

            map.put("schedulingId", ordScheduling.getId());
            List<OrdSourceDetail> sourceDetailList = ordSourceDetailMapper.selectList(map);
            for (OrdSourceDetail ordSourceDetail : sourceDetailList) {
                OrdSourceDetailHistory sourceDetailHistory = new OrdSourceDetailHistory();
                BeanUtil.copyProperties(ordSourceDetail, sourceDetailHistory);
                ordSourceDetailHistoryMapper.insert(sourceDetailHistory);
                ordSourceDetailMapper.deleteByPrimaryKey(ordSourceDetail.getId());
            }
        }
        return false;
    }


    @Override
    public List<OrdSchedulingWrapper> selectListByHospitalIdDoctorId(Long hospitalId, Long doctorId, String status, Long patId) {
        List<OrdSchedulingWrapper> schedulingWrapperList = new ArrayList<>();
        Map<String, Object> schedulingMap = new HashMap<String, Object>(8);
        schedulingMap.put("doctorId", doctorId);
        List<OrdSchedulingWrapper> schedulingList = ordSchedulingMapper.selectListWrapper(schedulingMap);
        Map<String, OrdSchedulingWrapper> stringListMap = new HashMap<String, OrdSchedulingWrapper>();

        String vip = "0";
        PubPatients patients = patientsMapper.selectByPrimaryKey(patId);

        for (OrdSchedulingWrapper scheduling : schedulingList) {
            if (LocalDate.now().isAfter(scheduling.getSchedulingTime())) {
                continue;
            }
            if (LocalDate.now().isEqual(scheduling.getSchedulingTime())) {
                continue;
            }
            vip = "0";
            if (Optional.ofNullable(patients).isPresent()) {
                if (Optional.ofNullable(patients.getPatMemGrade()).isPresent()) {
                    if (patients.getPatMemGrade().equals("1")) {
                        vip = "1";
                        if (LocalDate.now().plusWeeks(2).isBefore(scheduling.getSchedulingTime())) {
                            continue;
                        }
                    } else {
                        if (scheduling.getDoctorPracticeScope().equals("2")) {
                            continue;
                        }
                        if (LocalDate.now().plusWeeks(1).isBefore(scheduling.getSchedulingTime())) {
                            continue;
                        }
                        if (LocalDate.now().plusWeeks(1).isEqual(scheduling.getSchedulingTime())) {
                            if (LocalTime.now().isBefore(LocalTime.of(12, 0, 0))) {
                                continue;
                            }
                        }
                    }
                } else {
                    if (scheduling.getDoctorPracticeScope().equals("2")) {
                        continue;
                    }
                    if (LocalDate.now().plusWeeks(1).isBefore(scheduling.getSchedulingTime())) {
                        continue;
                    }
                    if (LocalDate.now().plusWeeks(1).isEqual(scheduling.getSchedulingTime())) {
                        if (LocalTime.now().isBefore(LocalTime.of(12, 0, 0))) {
                            continue;
                        }
                    }
                }
            } else {
                //如果用户信息为空 则VIP号源不显示
                if (scheduling.getDoctorPracticeScope().equals("2")) {
                    continue;
                }
                if (LocalDate.now().plusWeeks(1).isBefore(scheduling.getSchedulingTime())) {
                    continue;
                }
                if (LocalDate.now().plusWeeks(1).isEqual(scheduling.getSchedulingTime())) {
                    if (LocalTime.now().isBefore(LocalTime.of(12, 0, 0))) {
                        continue;
                    }
                }
            }

            int week = scheduling.getSchedulingTime().getDayOfWeek().getValue() + 1 > 7 ? 1 : scheduling.getSchedulingTime().getDayOfWeek().getValue() + 1;
            scheduling.setWeekWrapper(Week.of(week).toChinese());

            schedulingMap.clear();
            schedulingMap.put("schedulingId", scheduling.getId());
            if (!vip.equals("1")) {
                schedulingMap.put("type", "1");
                scheduling.setAmount(scheduling.getAppointmentAmount());
            } else {
                schedulingMap.put("status", "0");
            }
            List<OrdSourceDetail> sourceDetailList = ordSourceDetailMapper.selectList(schedulingMap);
            if (!vip.equals("1")) {
                scheduling.setAmount(sourceDetailList.size());
            }
            int num = 0;
            String sourceDetailKey = "sourceDetail:" + scheduling.getDoctorId() + ":" + scheduling.getId();
            for (OrdSourceDetail sourceDetail : sourceDetailList) {
                if (redisCacheTemplate.opsForSet().isMember(sourceDetailKey, sourceDetail.getId()) && sourceDetail.getStatus().equals("0")) {
                    num++;
                }
            }
            if (sourceDetailList.size() == 0) {
                continue;
            }
            scheduling.setAmountSurplus(num);
            if (scheduling.getState().equals("1")){
                scheduling.setAmount(-1);
                scheduling.setAmountSurplus(-1);
            }
            String key = LocalDateTimeUtil.formatNormal(scheduling.getSchedulingTime()) + scheduling.getWeekWrapper();
            System.out.println("string Map" + stringListMap);
            System.out.println("key" + key);
            System.out.println(stringListMap.containsKey(key));
            if (stringListMap.containsKey(key)) {

                OrdSchedulingWrapper schedulingWrapper = stringListMap.get(key);
                schedulingWrapper.setAmountSurplus(schedulingWrapper.getAmountSurplus());
                if (scheduling.getTimeState().equals(1)) {
                    if (scheduling.getSchedulingTime().equals(LocalDate.now())) {
                        if (LocalTime.now().isBefore(LocalTime.of(0, 30, 0))) {
                            schedulingWrapper.setSchedulingSW(scheduling);
                        }
                    } else {
                        schedulingWrapper.setSchedulingSW(scheduling);
                        System.out.println(schedulingWrapper);
                    }
                } else if (scheduling.getTimeState().equals(2)) {
                    if (scheduling.getSchedulingTime().equals(LocalDate.now())) {
                        if (LocalTime.now().isBefore(LocalTime.of(0, 30, 0))) {
                            schedulingWrapper.setSchedulingXW(scheduling);
                        }
                    } else {
                        schedulingWrapper.setSchedulingXW(scheduling);
                    }
                } else if (scheduling.getTimeState().equals(3)) {
                    schedulingWrapper.setSchedulingWJ(scheduling);
                    /* System.out.println(schedulingWrapper.getSchedulingWJ());*/
                    /* System.out.println("整体1"+schedulingWrapper);*/
                }

                stringListMap.put(key, schedulingWrapper);
            } else {
                OrdSchedulingWrapper schedulingWrapper = new OrdSchedulingWrapper();
                schedulingWrapper.setSchedulingDate(scheduling.getSchedulingTime());
                schedulingWrapper.setWeekWrapper(scheduling.getWeekWrapper());
                schedulingWrapper.setAmountSurplus(scheduling.getAmountSurplus());
                if (scheduling.getTimeState().equals(1)) {
                    if (scheduling.getSchedulingTime().equals(LocalDate.now())) {
                        if (LocalTime.now().isBefore(LocalTime.of(0, 30, 0))) {
                            schedulingWrapper.setSchedulingSW(scheduling);
                        }
                    } else {
                        schedulingWrapper.setSchedulingSW(scheduling);
                    }
                } else if (scheduling.getTimeState().equals(2)) {
                    if (scheduling.getSchedulingTime().equals(LocalDate.now())) {
                        if (LocalTime.now().isBefore(LocalTime.of(0, 30, 0))) {
                            schedulingWrapper.setSchedulingXW(scheduling);
                        }
                    } else {
                        schedulingWrapper.setSchedulingXW(scheduling);
                    }
                } else if (scheduling.getTimeState().equals(3)) {
                    schedulingWrapper.setSchedulingWJ(scheduling);
                }
                stringListMap.put(key, schedulingWrapper);

            }
        }

        for (OrdSchedulingWrapper value : stringListMap.values()) {
            schedulingWrapperList.add(value);

        }
        return schedulingWrapperList.stream().sorted(Comparator.comparing(OrdSchedulingWrapper::getSchedulingDate)).collect(Collectors.toList());
    }


    @Override
    public List<OptionItem<PubHospital>> selectListForOptions(Long hospitalId) {
        Map<String, Object> hospitalMap = new HashMap<String, Object>(8);
        if (!hospitalId.toString().equals("0")) {
            hospitalMap.put("id", hospitalId);
        }
        List<PubHospital> hospitalList = pubHospitalMapper.selectList(hospitalMap);
        List<OptionItem<PubHospital>> hospitalOptionItemList = new ArrayList<>();
        for (PubHospital hospital : hospitalList) {
            hospitalOptionItemList = selectListForOptionDepartments(hospital, hospitalOptionItemList);
        }
        return hospitalOptionItemList;
    }



    /**
     * 根据医院查科室
     *
     * @param hospital
     * @param hospitalOptionItemList
     */
    private List<OptionItem<PubHospital>> selectListForOptionDepartments(PubHospital hospital, List<OptionItem<PubHospital>> hospitalOptionItemList) {
        OptionItem<PubHospital> optionItemHos = new OptionItem<>();
        optionItemHos.setValue(hospital);
        optionItemHos.setLabel(hospital.getHosName());
        List<OptionItem> optionItemDepartmentsList = new ArrayList<>();
        Map<String, Object> departmentMap = new HashMap<String, Object>(8);
        departmentMap.clear();
        departmentMap.put("hospitalId", hospital.getId());
        departmentMap.put("depClinic", '1');
        departmentMap.put("status", '0');
        List<PubDepartments> departmentsList = departmentsMapper.selectList(departmentMap);
        // 科室
        for (PubDepartments departments : departmentsList) {
            optionItemDepartmentsList = selectListForOptionDoctor(departments, optionItemDepartmentsList);
        }
        optionItemHos.setChildren(optionItemDepartmentsList);
        hospitalOptionItemList.add(optionItemHos);
        return hospitalOptionItemList;
    }

    /**
     * 根据科室查医生
     *
     * @param departments
     * @param optionItemDepartmentsList
     */
    private List<OptionItem> selectListForOptionDoctor(PubDepartments departments, List<OptionItem> optionItemDepartmentsList) {
        Map<String, Object> doctorMap = new HashMap<String, Object>(8);
        doctorMap.clear();
        doctorMap.put("depId", departments.getId());
        doctorMap.put("status", "0");
        List<PubDoctor> doctorList = doctorMapper.selectList(doctorMap);
        OptionItem<PubDepartments> optionItemDep = new OptionItem<>();
        if (!CollectionUtils.isEmpty(doctorList)) {
            optionItemDep.setValue(departments);
            optionItemDep.setLabel(departments.getDepName());
        } else {
            return optionItemDepartmentsList;
        }
        // 医生
        List<OptionItem> optionItemDoctorList = new ArrayList<>();
        for (PubDoctor doctor : doctorList) {
            //排班
            List<OptionItem> optionItemSchedulingList = new ArrayList<>();
            doctorMap.clear();
            doctorMap.put("doctorId", doctor.getId());
            doctorMap.put("status", "0");
            List<OrdScheduling> schedulingList = ordSchedulingMapper.selectList(doctorMap);
            for (OrdScheduling scheduling : schedulingList) {
                if (LocalDate.now().equals(scheduling.getSchedulingTime())) {
                    continue;
                }
                optionItemSchedulingList = selectListForOptionScheduling(scheduling, optionItemSchedulingList);
            }
            if (!CollectionUtils.isEmpty(schedulingList)) {
                OptionItem<PubDoctor> optionItemDoctor = new OptionItem<>();
                optionItemDoctor.setValue(doctor);
                optionItemDoctor.setLabel(doctor.getDoctorName());
                optionItemDoctor.setChildren(optionItemSchedulingList);
                optionItemDoctorList.add(optionItemDoctor);
            }
        }
        optionItemDep.setChildren(optionItemDoctorList);
        optionItemDepartmentsList.add(optionItemDep);
        return optionItemDepartmentsList;
    }

    /**
     * 根据医生查排班
     *
     * @param scheduling
     * @param optionItemSchedulingList
     */
    private List<OptionItem> selectListForOptionScheduling(OrdScheduling scheduling, List<OptionItem> optionItemSchedulingList) {
        OptionItem<OrdScheduling> optionItemScheduling = new OptionItem<>();
        optionItemScheduling.setValue(scheduling);
        String label = scheduling.getTimeState().equals(1) ? "上午" : scheduling.getTimeState().equals(2) ? "下午" : "夜门诊";

        int week = scheduling.getSchedulingTime().getDayOfWeek().getValue() + 1 > 7 ? 1 : scheduling.getSchedulingTime().getDayOfWeek().getValue() + 1;

        label = LocalDateTimeUtil.format(scheduling.getSchedulingTime(), "yyyy-MM-dd") + "/" + Week.of(week).toChinese() + "/" + label + "/" + scheduling.getBinName();
        optionItemScheduling.setLabel(label);
        optionItemSchedulingList.add(optionItemScheduling);
        return optionItemSchedulingList;
    }

    @Override
    public OrdScheduling updateByPrimaryKeySelective(OrdScheduling record) {
//        long num = ChronoUnit.MINUTES.between(record.getStartTime(),record.getEndTime());
//        record.setAverageVisitTime(Integer.valueOf((int) (num/record.getAmount())));
        //预约号源编号
        OrdScheduling scheduling = ordSchedulingMapper.selectByPrimaryKey(record.getId());
        HashSet<String> hashSet = generateAppointmentSet(record);
        //设置过期时间
        Duration duration = Duration.between(LocalDateTime.now(), scheduling.getSchedulingTime().atTime(23, 59, 59));
        String schedulingKey = "scheduling:" + scheduling.getDoctorId() + ":" + scheduling.getId();

        Map<String, Object> map = new HashMap<String, Object>(8);
        map.put("schedulingId", record.getId());
        //此排班号源
        List<OrdSourceDetail> sourceDetailList = ordSourceDetailMapper.selectList(map);
        //生成现有号源明细
        String sourceDetailKey = "sourceDetail:" + scheduling.getDoctorId() + ":" + scheduling.getId();

        Integer current = sourceDetailList.size() + 1;
        if (sourceDetailList.size() < record.getAmount()) {

            for (Integer serialNumber = current; serialNumber <= record.getAmount(); serialNumber++) {
                List<OrdSourceDetail> sourceDetailList2 = ordSourceDetailMapper.selectList(map);
                LocalTime localTime = sourceDetailList2.get(sourceDetailList2.size() - 1).getVisitTime();
                OrdSourceDetail sourceDetail = new OrdSourceDetail();
                sourceDetail.setSchedulingId(scheduling.getId());
                sourceDetail.setSchedulingDate(scheduling.getSchedulingTime());
                if (hashSet.contains(serialNumber.toString())) {
                    sourceDetail.setType("1");
                } else {
                    sourceDetail.setType("0");
                }
                sourceDetail.setSchedulingId(scheduling.getId());
                sourceDetail.setVisitTime(localTime.plusMinutes(scheduling.getAverageVisitTime()));
                scheduling.setStartTime(sourceDetail.getVisitTime());
                sourceDetail.setSchedulingDate(scheduling.getSchedulingTime());
                sourceDetail.setTimeState(scheduling.getTimeState());
                sourceDetail.setSerialNumber(serialNumber.toString());
                sourceDetail.setDepId(scheduling.getDepId());
                sourceDetail.setDepName(scheduling.getDepName());
                sourceDetail.setDoctorId(scheduling.getDoctorId());
                sourceDetail.setDoctorName(scheduling.getDoctorName());
                sourceDetail.setBinId(scheduling.getBinId());
                sourceDetail.setHospitalId(scheduling.getHospitalId());
                sourceDetail.setBinName(scheduling.getBinName());
                sourceDetail.setState("0");
                //号源状态(正常0 未放号或已停诊或者已预约1)
                sourceDetail.setStatus("0");
                sourceDetailList.add(sourceDetail);
                ordSourceDetailMapper.insert(sourceDetail);
                sourceDetailList.add(sourceDetail);
                redisCacheTemplate.opsForSet().add(sourceDetailKey, sourceDetail.getId());
            }
        }
        if (redisCacheTemplate.hasKey(schedulingKey)) {
            Long amount = redisCacheTemplate.opsForSet().size(sourceDetailKey);
            redisCacheTemplate.opsForValue().set(schedulingKey, amount, duration);
            redisCacheTemplate.expire(sourceDetailKey, duration);
        }
        sourceDetailList = sourceDetailList.stream().filter(ordSourceDetail -> ordSourceDetail.getType().equals("1")).collect(Collectors.toList());
        record.setAppointmentAmount(sourceDetailList.size());
        ordSchedulingMapper.updateByPrimaryKeySelective(record);
        return scheduling;
    }

    /**
     * 生成第三方预约号源编码字典
     *
     * @param scheduling
     * @return
     */
    private HashSet<String> generateAppointmentSet(OrdScheduling scheduling) {
        HashSet<String> hashSet = new HashSet<String>(20);
        if (!Optional.ofNullable(scheduling.getAppointmentAmount()).isPresent()) {
            scheduling.setAppointmentAmount(scheduling.getAmount() - scheduling.getAppointmentBegin());
            scheduling.setAmountSurplus(scheduling.getAppointmentAmount());
        }
        if (scheduling.getAppointmentAmount().compareTo(0) > 0) {
            Integer serialNumber = scheduling.getAppointmentBegin();
            for (int i = 0; i < scheduling.getAppointmentAmount(); i++) {
                hashSet.add(serialNumber.toString());
                serialNumber = serialNumber + (scheduling.getIncrease() + 1);
            }
        }
        return hashSet;
    }


    /**
     * @Author chen
     * @Description //TODO 每天凌晨1:00-4:00上传科室和专家医生7天内的最新排班情况。若已经上传的排班无变化可以不用重复上传。
     * @Date  2021/5/21
     * @Param [hospitalId]
     * @return java.lang.String
     **/
    @Override
    public String jktSchedulingUpload(Long hospitalId) throws Exception {
        Map<String, Object> map = new HashMap<>();
        if (!hospitalId.toString().equals("0")) {
            map.put("hospitalId", hospitalId);
        }
        map.put("doctorPracticeScope","0");
        List<OrdScheduling> list = ordSchedulingMapper.selectList(map);
        for (OrdScheduling scheduling:list){
           LocalDate locadate = LocalDate.now().minusDays(-1);
            if (scheduling.getSchedulingTime().isAfter(locadate) && scheduling.getSchedulingTime().isBefore(locadate.plusWeeks(1))) {
                if (scheduling.getAppointmentAmount()>0 && scheduling.getState().equals("0")){
                        schedulingUpload(scheduling);
                }
            }
        }
        return "";
    }

    /**
     * @Author chen
     * @Description //TODO 每天凌晨1:00-4:00上传科室和专家医生7天内的最新排班情况。若已经上传的排班无变化可以不用重复上传。
     * @Date  2021/5/21
     * @Param []
     * @return void
     **/
    @Scheduled(cron = " 0 40 2 ? * *")
    @Override
    public void jktSchedulingUpload() throws Exception {
        Map<String, Object> map = new HashMap<>();
        List<OrdScheduling> list = ordSchedulingMapper.selectList(map);
        map.put("doctorPracticeScope","0");
        for (OrdScheduling scheduling:list){
            LocalDate locadate = LocalDate.now().minusDays(-1);
            if (scheduling.getSchedulingTime().isAfter(locadate) && locadate.plusWeeks(1).isBefore(scheduling.getSchedulingTime())) {
                if (scheduling.getAppointmentAmount()>0 && scheduling.getState().equals("0")){
                    schedulingUpload(scheduling);
                }
            }
        }

    }

    @Override
    public void jktSchedulingUploadSingle(Long id) throws Exception {
        OrdScheduling scheduling = ordSchedulingMapper.selectByPrimaryKey(id);
        schedulingUpload(scheduling);
    }

    /**
     * 健康通-上传排班
     * @param ordScheduling
     */
    private void schedulingUpload(OrdScheduling ordScheduling) throws Exception {
        jktFunc10004.setDeptId(ordScheduling.getDepId().toString());
        jktFunc10004.setDeptName(ordScheduling.getDepName());

        jktFunc10004.setDoctorId(ordScheduling.getDoctorId().toString());
        jktFunc10004.setDoctorName(ordScheduling.getDoctorName());

        jktFunc10004.setScheduleId(ordScheduling.getId().toString());
        jktFunc10004.setScheduleTime(ordScheduling.getTimeState().equals(1)?"1":"2");
        jktFunc10004.setScheduleDate(LocalDateTimeUtil.format(ordScheduling.getSchedulingTime(),"yyyyMMdd"));
        Map<String,Object> map =new HashMap<>(2);
        map.clear();
        map.put("schedulingId",ordScheduling.getId());
        map.put("type","1");
        List<OrdSourceDetail> list = ordSourceDetailMapper.selectList(map);
        jktFunc10004.setRegTotal(list.size()+"");

        List<OrdSourceDetail> sourceDetailList = new ArrayList();
        for (OrdSourceDetail sourceDetail : list) {
            //号源明细类型 0院内号源和1第三方号源(平台、官网)
            String sourceDetailKey="sourceDetail:"+sourceDetail.getDoctorId()+":"+sourceDetail.getSchedulingId();
            //if ("0".equals(sourceDetail.getStatus()) && redisCacheTemplate.opsForSet().isMember(sourceDetailKey,sourceDetail.getId())) {
            if ("0".equals(sourceDetail.getStatus()) && redisCacheTemplate.opsForSet().isMember(sourceDetailKey,sourceDetail.getId())) {
                sourceDetailList.add(sourceDetail);
            }
        }
        if (ordScheduling.getStatus().equals("1")){
            jktFunc10004.setRegNum(ordScheduling.getAppointmentAmount()+"");
        }else {
            jktFunc10004.setRegNum(sourceDetailList.size()+"");
        }
        PubBindInfo bindInfo = pubBindInfoMapper.selectByPrimaryKey(ordScheduling.getBinId());
        jktFunc10004.setRegFee(bindInfo.getGhf()+"");
        jktFunc10004.setScheduleState(ordScheduling.getStatus().equals("0")?"0":"1");
        List<JSON> jktFun10004InList = new ArrayList<>();
        sortMap(BeanUtil.beanToMap(jktFunc10004));
        jktFun10004InList.add(JSONUtil.parse(jktFunc10004));
        Map<String,Object> FuncMap =  new HashMap<>();
        FuncMap.put("list",jktFun10004InList);
        JktOutParameter outParameter = JKTUtil.jThealthPost("10004",FuncMap, jThealth);
        if (outParameter.getSuccess().equals(1)){
            sourceDetailUpload(list,ordScheduling);
        }




    }

    /**
     * 健康通-上传号源
     * @param sourceDetailList
     */
    private void sourceDetailUpload(List<OrdSourceDetail> sourceDetailList,OrdScheduling ordScheduling) throws Exception {

        List<JSON> jktFunc10005List =  new ArrayList<>();
        for (OrdSourceDetail sourceDetail:sourceDetailList){
            jktFunc10005.setDeptId(sourceDetail.getDepId().toString());
            jktFunc10005.setDeptName(sourceDetail.getDepName());

            jktFunc10005.setDoctorId(sourceDetail.getDoctorId().toString());
            jktFunc10005.setDoctorName(sourceDetail.getDoctorName());

            jktFunc10005.setScheduleId(sourceDetail.getSchedulingId().toString());

            jktFunc10005.setPointId(sourceDetail.getId().toString());
            jktFunc10005.setPointNo(sourceDetail.getSerialNumber());

            jktFunc10005.setScheduleTime(sourceDetail.getTimeState().equals(1)?"1":"2");
            jktFunc10005.setScheduleDate(LocalDateTimeUtil.format(sourceDetail.getSchedulingDate(),"yyyyMMdd"));

            jktFunc10005.setRegTime(sourceDetail.getVisitTime().toString()+"-"+sourceDetail.getVisitTime().plusMinutes(ordScheduling.getAverageVisitTime()).toString());
            PubBindInfo bindInfo = pubBindInfoMapper.selectByPrimaryKey(sourceDetail.getBinId());
            jktFunc10005.setRegFee(bindInfo.getGhf()+"");
            jktFunc10005.setRegStatus(sourceDetail.getStatus());
            jktFunc10005List.add(JSONUtil.parse(jktFunc10005));
        }
        Map<String,Object> FuncMap =  new HashMap<>();
        FuncMap.put("list",jktFunc10005List);
        JKTUtil.jThealthPost("10005",FuncMap, jThealth);
    }


    private void jktCancel(OrdScheduling scheduling) throws Exception {
        if (scheduling.getStatus().equals("1")){
            cancelUpload(scheduling);
        }else {
            revokeCancelUpload(scheduling);
        }
    }
    /**
     * 上传停诊通知
     * @param ordScheduling
     */
    private void cancelUpload(OrdScheduling ordScheduling) throws Exception {
        jktFunc10006.setDeptId(ordScheduling.getDepId().toString());
        jktFunc10006.setDeptName(ordScheduling.getDepName());

        jktFunc10006.setDoctorId(ordScheduling.getDoctorId().toString());
        jktFunc10006.setDoctorName(ordScheduling.getDoctorName());

        jktFunc10006.setScheduleId(ordScheduling.getId().toString());
        jktFunc10006.setScheduleTime(ordScheduling.getTimeState().equals(1)?"1":"2");
        jktFunc10006.setScheduleDate(LocalDateTimeUtil.format(ordScheduling.getSchedulingTime(),"yyyyMMdd"));
        jktFunc10006.setReason(ordScheduling.getStopServiceReason());

        List<JSON> jktFun10006InList = new ArrayList<>();
        sortMap(BeanUtil.beanToMap(jktFunc10006));
        jktFun10006InList.add(JSONUtil.parse(jktFunc10006));
        Map<String,Object> FuncMap =  new HashMap<>();
        FuncMap.put("list",jktFun10006InList);
        JKTUtil.jThealthPost("10006",FuncMap, jThealth);
    }

    /**
     * 删除之前的停诊通知，恢复诊疗。
     * @param ordScheduling
     */
    private void revokeCancelUpload(OrdScheduling ordScheduling) throws Exception {

        jktFunc10007.setDeptId(ordScheduling.getDepId().toString());
        jktFunc10007.setDeptName(ordScheduling.getDepName());

        jktFunc10007.setDoctorId(ordScheduling.getDoctorId().toString());
        jktFunc10007.setDoctorName(ordScheduling.getDoctorName());

        jktFunc10007.setScheduleId(ordScheduling.getId().toString());
        jktFunc10007.setScheduleTime(ordScheduling.getTimeState().equals(1)?"1":"2");
        jktFunc10007.setScheduleDate(LocalDateTimeUtil.format(ordScheduling.getSchedulingTime(),"yyyyMMdd"));

        List<JSON> jktFun10007InList = new ArrayList<>();
        sortMap(BeanUtil.beanToMap(jktFunc10007));
        jktFun10007InList.add(JSONUtil.parse(jktFunc10007));
        Map<String,Object> FuncMap =  new HashMap<>();
        FuncMap.put("list",jktFun10007InList);
        JKTUtil.jThealthPost("10007",FuncMap, jThealth);
    }



}
